From 7dc9afed06334b83acd94717bd033d9dd94706a3 Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Thu, 30 Nov 2006 14:44:58 +0000 Subject: [PATCH] [XEND] Remove SXP from most parts of Xend. Attempt to get rid of most SXP dependency in Xend except in configuration parsing and certain places where it is required. XendConfig now stores configuration options similar to Xen API VM and devices attributes but exports an SXP version to certain things like xm and XendCheckpoint. All access to VM and device attributes should now use Python dictionaries rather than the SXP parser. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendAPI.py | 12 +- tools/python/xen/xend/XendCheckpoint.py | 4 +- tools/python/xen/xend/XendConfig.py | 1181 +++++++++-------- tools/python/xen/xend/XendDomain.py | 11 +- tools/python/xen/xend/XendDomainInfo.py | 320 +++-- tools/python/xen/xend/image.py | 134 +- tools/python/xen/xend/server/DevController.py | 7 +- tools/python/xen/xend/server/blkif.py | 21 +- tools/python/xen/xend/server/iopif.py | 4 +- tools/python/xen/xend/server/irqif.py | 2 +- tools/python/xen/xend/server/netif.py | 24 +- tools/python/xen/xend/server/pciif.py | 67 +- tools/python/xen/xend/server/pciquirk.py | 43 +- .../xen/xend/server/tests/test_controllers.py | 6 +- tools/python/xen/xend/server/tpmif.py | 12 +- tools/python/xen/xm/main.py | 4 +- 16 files changed, 977 insertions(+), 875 deletions(-) diff --git a/tools/python/xen/xend/XendAPI.py b/tools/python/xen/xend/XendAPI.py index 4f553b9bc3..081de0cf11 100644 --- a/tools/python/xen/xend/XendAPI.py +++ b/tools/python/xen/xend/XendAPI.py @@ -730,11 +730,11 @@ class XendAPI: def vm_get_memory_dynamic_max(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_todo() + return xen_api_success(dom.get_memory_dynamic_max()) def vm_get_memory_dynamic_min(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_todo() + return xen_api_success(dom.get_memory_dynamic_min()) def vm_get_VCPUs_policy(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) @@ -798,11 +798,11 @@ class XendAPI: def vm_get_builder(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_todo() + return xen_api_success(dom.get_builder()) def vm_get_boot_method(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_success('') + return xen_api_success(dom.get_boot_method()) def vm_get_kernel_kernel(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) @@ -969,8 +969,8 @@ class XendAPI: 'resident_on': XendNode.instance().uuid, 'memory_static_min': xeninfo.get_memory_static_min(), 'memory_static_max': xeninfo.get_memory_static_max(), - 'memory_dynamic_min': xeninfo.get_memory_static_min(), - 'memory_dynamic_max': xeninfo.get_memory_static_max(), + 'memory_dynamic_min': xeninfo.get_memory_dynamic_min(), + 'memory_dynamic_max': xeninfo.get_memory_dynamic_max(), 'memory_actual': xeninfo.get_memory_static_min(), 'vcpus_policy': xeninfo.get_vcpus_policy(), 'vcpus_params': xeninfo.get_vcpus_params(), diff --git a/tools/python/xen/xend/XendCheckpoint.py b/tools/python/xen/xend/XendCheckpoint.py index b7c964d70a..707a9c5c3c 100644 --- a/tools/python/xen/xend/XendCheckpoint.py +++ b/tools/python/xen/xend/XendCheckpoint.py @@ -18,8 +18,8 @@ import xen.lowlevel.xc from xen.xend import balloon, sxp from xen.xend.XendError import XendError, VmError from xen.xend.XendLogging import log -from xen.xend.XendConstants import * from xen.xend.XendConfig import XendConfig +from xen.xend.XendConstants import * SIGNATURE = "LinuxGuestRecord" XC_SAVE = "xc_save" @@ -137,7 +137,7 @@ def restore(xd, fd, dominfo = None, paused = False): vmconfig = p.get_val() if dominfo: - dominfo.update(XendConfig(sxp = vmconfig), refresh = False) + dominfo.update(XendConfig(sxp_obj = vmconfig), refresh = False) dominfo.resume() else: dominfo = xd.restore_(vmconfig) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index da7898c72c..df124c06ca 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -31,31 +31,34 @@ from xen.xend.XendConstants import DOM_STATE_HALTED XendConfig API XendConfig will try to mirror as closely the Xen API VM Struct - providing a backwards compatibility mode for SXP dumping, loading. + with extra parameters for those options that are not supported. """ +def reverse_dict(adict): + """Return the reverse mapping of a dictionary.""" + return dict([(v, k) for k, v in adict.items()]) -LEGACY_CFG_TO_XENAPI_CFG = { +# Mapping from XendConfig configuration keys to the old +# legacy configuration keys that map directly. + +XENAPI_CFG_TO_LEGACY_CFG = { 'uuid': 'uuid', - 'vcpus': 'vcpus_number', - 'maxmem': 'memory_static_max', - 'memory': 'memory_static_min', - 'name': 'name_label', - 'on_poweroff': 'actions_after_shutdown', - 'on_reboot': 'actions_after_reboot', - 'on_crash': 'actions_after_crash', - 'bootloader': 'boot_method', - 'kernel_kernel': 'kernel_kernel', - 'kernel_initrd': 'kernel_initrd', - 'kernel_args': 'kernel_args', - } - -XENAPI_CFG_CUSTOM_TRANSLATE = [ - 'vifs', - 'vbds', - ] + 'vcpus_number': 'vcpus', + 'memory_static_min': 'memory', + 'memory_static_max': 'maxmem', + 'name_label': 'name', + 'actions_after_shutdown': 'on_poweroff', + 'actions_after_reboot': 'on_reboot', + 'actions_after_crash': 'on_crash', + 'platform_localtime': 'localtime', +} +LEGACY_CFG_TO_XENAPI_CFG = reverse_dict(XENAPI_CFG_TO_LEGACY_CFG) + +# Mapping from XendConfig configuration keys to the old +# legacy configuration keys that are found in the 'image' +# SXP object. XENAPI_HVM_CFG = { 'platform_std_vga': 'std-vga', 'platform_serial' : 'serial', @@ -64,7 +67,10 @@ XENAPI_HVM_CFG = { 'platform_keymap' : 'keymap', } -XENAPI_UNSUPPORTED_IN_LEGACY_CFG = [ +# List of XendConfig configuration keys that have no equivalent +# in the old world. + +XENAPI_UNSUPPORTED_BY_LEGACY_CFG = [ 'name_description', 'user_version', 'is_a_template', @@ -85,11 +91,116 @@ XENAPI_UNSUPPORTED_IN_LEGACY_CFG = [ 'platform_clock_offset', 'platform_enable_audio', 'platform_keymap', + 'boot_method', 'builder', 'grub_cmdline', 'pci_bus', 'otherconfig' - ] +] + +# List of legacy configuration keys that have no equivalent in the +# Xen API, but are still stored in XendConfig. + +LEGACY_UNSUPPORTED_BY_XENAPI_CFG = [ + # roundtripped (dynamic, unmodified) + 'shadow_memory', + 'security', + 'vcpu_avail', + 'cpu_weight', + 'cpu_cap', + 'bootloader', + 'bootloader_args', + 'features', + # read/write + 'on_xend_start', + 'on_xend_stop', + # read-only + 'domid', + 'start_time', + 'cpu_time', + 'online_vcpus', + # write-once + 'cpu', + 'cpus', +] + +LEGACY_CFG_TYPES = { + 'uuid': str, + 'name': str, + 'vcpus': int, + 'vcpu_avail': int, + 'memory': int, + 'shadow_memory': int, + 'maxmem': int, + 'start_time': float, + 'cpu_cap': int, + 'cpu_weight': int, + 'cpu_time': float, + 'bootloader': str, + 'bootloader_args': str, + 'features': str, + 'localtime': int, + 'name': str, + 'on_poweroff': str, + 'on_reboot': str, + 'on_crash': str, + 'on_xend_stop': str, + 'on_xend_start': str, +} + +# Values that should be stored in xenstore's /vm/ that is used +# by Xend. Used in XendDomainInfo to restore running VM state from +# xenstore. +LEGACY_XENSTORE_VM_PARAMS = [ + 'uuid', + 'name', + 'vcpus', + 'vcpu_avail', + 'memory', + 'shadow_memory', + 'maxmem', + 'start_time', + 'name', + 'on_poweroff', + 'on_crash', + 'on_reboot', + 'on_xend_start', + 'on_xend_stop', +] + +LEGACY_IMAGE_CFG = [ + ('root', str), + ('ip', str), + ('nographic', int), + ('vnc', int), + ('sdl', int), + ('vncdisplay', int), + ('vncunused', int), +] + +LEGACY_IMAGE_HVM_CFG = [ + ('device_model', str), + ('display', str), + ('xauthority', str), + ('vncconsole', int), + ('pae', int), + ('apic', int), + ('acpi', int), + ('serial', str), +] + +LEGACY_IMAGE_HVM_DEVICES_CFG = [ + ('boot', str), + ('fda', str), + ('fdb', str), + ('soundhw', str), + ('isa', str), + ('vcpus', int), + ('acpi', int), + ('usb', str), + ('usbdevice', str), +] + # configuration params that need to be converted to ints @@ -102,74 +213,11 @@ XENAPI_INT_CFG = [ 'memory_static_max', 'memory_dynamic_min', 'memory_dynamic_max', + 'memory_actual', 'tpm_instance', 'tpm_backend', ] -## -## Xend Configuration Parameters -## - - -# All parameters of VMs that may be configured on-the-fly, or at start-up. -VM_CONFIG_ENTRIES = [ - ('name', str), - ('on_crash', str), - ('on_poweroff', str), - ('on_reboot', str), - ('on_xend_start', str), - ('on_xend_stop', str), -] - -# All entries written to the store. This is VM_CONFIG_ENTRIES, plus those -# entries written to the store that cannot be reconfigured on-the-fly. -VM_STORE_ENTRIES = [ - ('uuid', str), - ('vcpus', int), - ('vcpu_avail', int), - ('memory', int), - ('maxmem', int), - ('start_time', float), -] - -VM_STORED_ENTRIES = VM_CONFIG_ENTRIES + VM_STORE_ENTRIES - -# Configuration entries that we expect to round-trip -- be read from the -# config file or xc, written to save-files (i.e. through sxpr), and reused as -# config on restart or restore, all without munging. Some configuration -# entries are munged for backwards compatibility reasons, or because they -# don't come out of xc in the same form as they are specified in the config -# file, so those are handled separately. - -ROUNDTRIPPING_CONFIG_ENTRIES = [ - ('uuid', str), - ('vcpus', int), - ('vcpu_avail', int), - ('cpu_cap', int), - ('cpu_weight', int), - ('memory', int), - ('shadow_memory', int), - ('maxmem', int), - ('bootloader', str), - ('bootloader_args', str), - ('features', str), - ('localtime', int), -] -ROUNDTRIPPING_CONFIG_ENTRIES += VM_CONFIG_ENTRIES - -## Static Configuration - -STATIC_CONFIG_ENTRIES = [ - ('cpu', int), - ('cpus', str), - ('image', list), - ('security', list), # TODO: what if null? -] - -DEPRECATED_ENTRIES = [ - ('restart', str), -] - ## ## Config Choices ## @@ -178,245 +226,152 @@ CONFIG_RESTART_MODES = ('restart', 'destroy', 'preserve', 'rename-restart') CONFIG_OLD_DOM_STATES = ('running', 'blocked', 'paused', 'shutdown', 'crashed', 'dying') -## -## Defaults -## - -def DEFAULT_VCPUS(info): - if 'max_vcpu_id' in info: return int(info['max_vcpu_id']) + 1 - else: return 1 - -DEFAULT_CONFIGURATION = ( - ('uuid', lambda info: uuid.createString()), - ('name', lambda info: 'Domain-' + info['uuid']), - - ('on_poweroff', lambda info: 'destroy'), - ('on_reboot', lambda info: 'restart'), - ('on_crash', lambda info: 'restart'), - ('features', lambda info: ''), - - - ('memory', lambda info: 0), - ('shadow_memory',lambda info: 0), - ('maxmem', lambda info: 0), - ('bootloader', lambda info: None), - ('bootloader_args', lambda info: None), - ('backend', lambda info: []), - ('device', lambda info: {}), - ('image', lambda info: None), - ('security', lambda info: []), - ('on_xend_start', lambda info: 'ignore'), - ('on_xend_stop', lambda info: 'ignore'), - - ('cpus', lambda info: []), - ('cpu_cap', lambda info: 0), - ('cpu_weight', lambda info: 256), - ('vcpus', lambda info: DEFAULT_VCPUS(info)), - ('online_vcpus', lambda info: info['vcpus']), - ('max_vcpu_id', lambda info: info['vcpus']-1), - ('vcpu_avail', lambda info: (1</image value and xm list.""" + image = [self['image'].get('type', 'linux')] + if self.has_key('kernel_kernel'): + image.append(['kernel', self['kernel_kernel']]) + if self.has_key('kernel_initrd') and self['kernel_initrd']: + image.append(['ramdisk', self['kernel_initrd']]) + if self.has_key('kernel_args') and self['kernel_args']: + image.append(['args', self['kernel_args']]) + + for arg, conv in LEGACY_IMAGE_CFG: + if self['image'].has_key(arg): + image.append([arg, self['image'][arg]]) + + if 'hvm' in self['image']: + for arg, conv in LEGACY_IMAGE_HVM_CFG: + if self['image']['hvm'].has_key(arg): + image.append([arg, self['image']['hvm'][arg]]) + + if 'hvm' in self['image'] and 'devices' in self['image']['hvm']: + for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG: + if self['image']['hvm']['devices'].has_key(arg): + image.append([arg, + self['image']['hvm']['devices'][arg]]) + + return image + + def update_with_image_sxp(self, image_sxp): + # Convert Legacy "image" config to Xen API kernel_* + # configuration + self['kernel_kernel'] = sxp.child_value(image_sxp, 'kernel','') + self['kernel_initrd'] = sxp.child_value(image_sxp, 'ramdisk','') + kernel_args = sxp.child_value(image_sxp, 'args', '') + + # attempt to extract extra arguments from SXP config + arg_ip = sxp.child_value(image_sxp, 'ip') + if arg_ip and not re.search(r'ip=[0-9\.]', kernel_args): + kernel_args += ' ip=%s' % arg_ip + arg_root = sxp.child_value(image_sxp, 'root') + if arg_root and not re.search(r'root=', kernel_args): + kernel_args += ' root=%s' % arg_root + self['kernel_args'] = kernel_args + + # Store image SXP in python dictionary format + image = {} + image['type'] = sxp.name(image_sxp) + for arg, conv in LEGACY_IMAGE_CFG: + val = sxp.child_value(image_sxp, arg, None) + if val != None: + image[arg] = conv(val) + + image_hvm = {} + for arg, conv in LEGACY_IMAGE_HVM_CFG: + val = sxp.child_value(image_sxp, arg, None) + if val != None: + image_hvm[arg] = conv(val) + + image_hvm_devices = {} + for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG: + val = sxp.child_value(image_sxp, arg, None) + if val != None: + image_hvm_devices[arg] = conv(val) + + if image_hvm or image_hvm_devices: + image['hvm'] = image_hvm + image['hvm']['devices'] = image_hvm_devices + + self['image'] = image + + for apikey, imgkey in XENAPI_HVM_CFG.items(): + val = sxp.child(image_sxp, imgkey, None) + if val != None: + self[apikey] = val + + # # debugging # diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 839acc8da6..b21f762d13 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -433,6 +433,11 @@ class XendDomain: """ log.debug("Adding Domain: %s" % info.getDomid()) self.domains[info.getDomid()] = info + + # update the managed domains with a new XendDomainInfo object + # if we are keeping track of it. + if info.get_uuid() in self.managed_domains: + self._managed_domain_register(info) def _remove_domain(self, info, domid = None): """Remove the domain from the list of running domains @@ -669,7 +674,7 @@ class XendDomain: self.domains_lock.acquire() try: try: - xeninfo = XendConfig(xenapi_vm = xenapi_vm) + xeninfo = XendConfig(xapi = xenapi_vm) dominfo = XendDomainInfo.createDormant(xeninfo) log.debug("Creating new managed domain: %s: %s" % (dominfo.getName(), dominfo.get_uuid())) @@ -873,8 +878,8 @@ class XendDomain: self.domains_lock.acquire() try: try: - xeninfo = XendConfig(sxp = config) - dominfo = XendDomainInfo.createDormant(xeninfo) + domconfig = XendConfig(sxp_obj = config) + dominfo = XendDomainInfo.createDormant(domconfig) log.debug("Creating new managed domain: %s" % dominfo.getName()) self._managed_domain_register(dominfo) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 26428a0304..fdf5dc4d71 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -38,10 +38,9 @@ from xen.util.blkif import blkdev_uname_to_file from xen.util import security from xen.xend import balloon, sxp, uuid, image, arch -from xen.xend import XendRoot, XendNode +from xen.xend import XendRoot, XendNode, XendConfig from xen.xend.XendBootloader import bootloader -from xen.xend.XendConfig import XendConfig from xen.xend.XendError import XendError, VmError from xen.xend.XendDevices import XendDevices from xen.xend.xenstore.xstransact import xstransact, complete @@ -145,7 +144,7 @@ def create(config): """ log.debug("XendDomainInfo.create(%s)", config) - vm = XendDomainInfo(XendConfig(sxp = config)) + vm = XendDomainInfo(XendConfig.XendConfig(sxp_obj = config)) try: vm.start() except: @@ -175,10 +174,9 @@ def recreate(info, priv): assert not info['dying'] - xeninfo = XendConfig(cfg = info) + xeninfo = XendConfig.XendConfig(dominfo = info) domid = xeninfo['domid'] - uuid1 = xeninfo['handle'] - xeninfo['uuid'] = uuid.toString(uuid1) + uuid1 = uuid.fromString(xeninfo['uuid']) needs_reinitialising = False dompath = GetDomainPath(domid) @@ -236,7 +234,7 @@ def recreate(info, priv): def restore(config): """Create a domain and a VM object to do a restore. - @param config: Domain configuration object + @param config: Domain SXP configuration @type config: list of lists. (see C{create}) @rtype: XendDomainInfo @@ -246,7 +244,8 @@ def restore(config): """ log.debug("XendDomainInfo.restore(%s)", config) - vm = XendDomainInfo(XendConfig(sxp = config), resume = True) + vm = XendDomainInfo(XendConfig.XendConfig(sxp_obj = config), + resume = True) try: vm.resume() return vm @@ -254,24 +253,24 @@ def restore(config): vm.destroy() raise -def createDormant(xeninfo): +def createDormant(domconfig): """Create a dormant/inactive XenDomainInfo without creating VM. This is for creating instances of persistent domains that are not yet start. - @param xeninfo: Parsed configuration - @type xeninfo: dictionary + @param domconfig: Parsed configuration + @type domconfig: XendConfig object @rtype: XendDomainInfo @return: A up and running XendDomainInfo instance @raise XendError: Errors with configuration. """ - log.debug("XendDomainInfo.createDormant(%s)", xeninfo) + log.debug("XendDomainInfo.createDormant(%s)", domconfig) # domid does not make sense for non-running domains. - xeninfo.pop('domid', None) - vm = XendDomainInfo(XendConfig(cfg = xeninfo)) + domconfig.pop('domid', None) + vm = XendDomainInfo(domconfig) return vm def domain_by_name(name): @@ -383,14 +382,6 @@ class XendDomainInfo: #if not self._infoIsSet('uuid'): # self.info['uuid'] = uuid.toString(uuid.create()) - #REMOVE: domid logic can be shortened - #if domid is not None: - # self.domid = domid - #elif info.has_key('dom'): - # self.domid = int(info['dom']) - #else: - # self.domid = None - self.vmpath = XS_VMROOT + self.info['uuid'] self.dompath = dompath @@ -403,6 +394,7 @@ class XendDomainInfo: self.vmWatch = None self.shutdownWatch = None self.shutdownStartTime = None + self._resume = resume self.state = DOM_STATE_HALTED self.state_updated = threading.Condition() @@ -416,8 +408,7 @@ class XendDomainInfo: if augment: self._augmentInfo(priv) - self._checkName(self.info['name']) - self.setResume(resume) + self._checkName(self.info['name_label']) # @@ -477,7 +468,7 @@ class XendDomainInfo: if self.domid == 0: raise XendError('Domain 0 cannot be shutdown') - if not reason in DOMAIN_SHUTDOWN_REASONS.values(): + if reason not in DOMAIN_SHUTDOWN_REASONS.values(): raise XendError('Invalid reason: %s' % reason) self._storeDom("control/shutdown", reason) @@ -512,12 +503,14 @@ class XendDomainInfo: """Create a new device. @param dev_config: device configuration - @type dev_config: dictionary (parsed config) + @type dev_config: SXP object (parsed config) """ log.debug("XendDomainInfo.device_create: %s" % dev_config) dev_type = sxp.name(dev_config) - devid = self._createDevice(dev_type, dev_config) - self.info.device_add(dev_type, cfg_sxp = dev_config) + dev_uuid = self.info.device_add(dev_type, cfg_sxp = dev_config) + dev_config_dict = self.info['devices'][dev_uuid][1] + log.debug("XendDomainInfo.device_create: %s" % dev_config_dict) + devid = self._createDevice(dev_type, dev_config_dict) self._waitForDevice(dev_type, devid) return self.getDeviceController(dev_type).sxpr(devid) @@ -525,12 +518,26 @@ class XendDomainInfo: """Configure an existing device. @param dev_config: device configuration - @type dev_config: dictionary (parsed config) + @type dev_config: SXP object (parsed config) @param devid: device id @type devid: int + @return: Returns True if successfully updated device + @rtype: boolean """ deviceClass = sxp.name(dev_config) - self._reconfigureDevice(deviceClass, devid, dev_config) + + # look up uuid of the device + dev_control = self.getDeviceController(deviceClass) + dev_sxpr = dev_control.sxpr(devid) + dev_uuid = sxp.child_value(sxpr, 'uuid') + if not dev_uuid: + return False + + self.info.device_update(dev_uuid, dev_config) + dev_config_dict = self.info['devices'].get(dev_uuid) + if dev_config_dict: + dev_control.reconfigureDevice(devid, dev_config_dict[1]) + return True def waitForDevices(self): """Wait for this domain's configured devices to connect. @@ -567,12 +574,12 @@ class XendDomainInfo: @param target: In MiB. """ log.debug("Setting memory target of domain %s (%d) to %d MiB.", - self.info['name'], self.domid, target) + self.info['name_label'], self.domid, target) if target <= 0: raise XendError('Invalid memory size') - self.info['memory'] = target + self.info['memory_static_min'] = target self.storeVm("memory", target) self._storeDom("memory/target", target << 10) @@ -581,8 +588,8 @@ class XendDomainInfo: # We include the domain name and ID, to help xm. sxpr = ['domain', ['domid', self.domid], - ['name', self.info['name']], - ['vcpu_count', self.info['online_vcpus']]] + ['name', self.info['name_label']], + ['vcpu_count', self.info['vcpus_number']]] for i in range(0, self.info['max_vcpu_id']+1): info = xc.vcpu_getinfo(self.domid, i) @@ -610,30 +617,40 @@ class XendDomainInfo: values taken from the store. This recovers those values known to xend but not to the hypervisor. """ - def useIfNeeded(name, val): - if not self._infoIsSet(name) and val is not None: - self.info[name] = val - + augment_entries = XendConfig.LEGACY_XENSTORE_VM_PARAMS[:] if priv: - entries = VM_STORE_ENTRIES[:] - entries.remove(('memory', int)) - entries.remove(('maxmem', int)) - else: - entries = VM_STORE_ENTRIES - entries.append(('image', str)) - entries.append(('security', str)) + augment_entries.remove('memory') + augment_entries.remove('maxmem') - map(lambda x, y: useIfNeeded(x[0], y), entries, - self._readVMDetails(entries)) + vm_config = self._readVMDetails([(k, XendConfig.LEGACY_CFG_TYPES[k]) + for k in augment_entries]) + + # make returned lists into a dictionary + vm_config = dict(zip(augment_entries, vm_config)) + + for arg in augment_entries: + xapicfg = arg + val = vm_config[arg] + if val != None: + if arg in XendConfig.LEGACY_CFG_TO_XENAPI_CFG: + xapiarg = XendConfig.LEGACY_CFG_TO_XENAPI_CFG[arg] + self.info[xapiarg] = val + else: + self.info[arg] = val - devices = [] + # read image value + image_sxp = self._readVm('image') + if image_sxp: + self.info.update_with_image_sxp(sxp.from_string(image_sxp)) + # read devices + devices = [] for devclass in XendDevices.valid_devices(): devconfig = self.getDeviceController(devclass).configurations() if devconfig: devices.extend(map(lambda conf: (devclass, conf), devconfig)) - if not self.info['device'] and devices is not None: + if not self.info['devices'] and devices is not None: for device in devices: self.info.device_add(device[0], cfg_sxp = device) @@ -678,16 +695,16 @@ class XendDomainInfo: def _recreateDomFunc(self, t): t.remove() t.mkdir() - t.set_permissions({ 'dom' : self.domid }) + t.set_permissions({'dom' : self.domid}) t.write('vm', self.vmpath) def _storeDomDetails(self): to_store = { 'domid': str(self.domid), 'vm': self.vmpath, - 'name': self.info['name'], + 'name': self.info['name_label'], 'console/limit': str(xroot.get_console_limit() * 1024), - 'memory/target': str(self.info['memory'] * 1024) + 'memory/target': str(self.info['memory_static_min'] * 1024) } def f(n, v): @@ -713,7 +730,7 @@ class XendDomainInfo: return 'offline' result = {} - for v in range(0, self.info['vcpus']): + for v in range(0, self.info['vcpus_number']): result["cpu/%d/availability" % v] = availability(v) return result @@ -735,19 +752,29 @@ class XendDomainInfo: log.trace("XendDomainInfo.storeChanged"); changed = False + + # Check whether values in the configuration have + # changed in Xenstore. - def f(x, y): - if y is not None and self.info[x[0]] != y: - self.info[x[0]] = y - changed = True - - map(f, VM_CONFIG_PARAMS, self._readVMDetails(VM_CONFIG_PARAMS)) - - im = self._readVm('image') - current_im = self.info['image'] - if (im is not None and - (current_im is None or sxp.to_string(current_im) != im)): - self.info['image'] = sxp.from_string(im) + cfg_vm = ['name', 'on_poweroff', 'on_reboot', 'on_crash'] + + vm_details = self._readVMDetails([(k,XendConfig.LEGACY_CFG_TYPES[k]) + for k in cfg_vm]) + + # convert two lists into a python dictionary + vm_details = dict(zip(cfg_vm, vm_details)) + + for arg, val in vm_details.items(): + if arg in XendConfig.LEGACY_CFG_TO_XENAPI_CFG: + xapiarg = XendConfig.LEGACY_CFG_TO_XENAPI_CFG[arg] + if val != None and val != self.info[xapiarg]: + self.info[xapiarg] = val + changed= True + + # Check whether image definition has been updated + image_sxp = self._readVm('image') + if image_sxp and image_sxp != self.info.image_sxpr(): + self.info.update_with_image_sxp(sxp.from_string(image_sxp)) changed = True if changed: @@ -791,11 +818,11 @@ class XendDomainInfo: def setName(self, name): self._checkName(name) - self.info['name'] = name + self.info['name_label'] = name self.storeVm("name", name) def getName(self): - return self.info['name'] + return self.info['name_label'] def getDomainPath(self): return self.dompath @@ -816,7 +843,7 @@ class XendDomainInfo: return self.info['features'] def getVCpuCount(self): - return self.info['vcpus'] + return self.info['vcpus_number'] def setVCpuCount(self, vcpus): self.info['vcpu_avail'] = (1 << vcpus) - 1 @@ -828,19 +855,19 @@ class XendDomainInfo: def getMemoryTarget(self): """Get this domain's target memory size, in KB.""" - return self.info['memory'] * 1024 + return self.info['memory_static_min'] * 1024 def getResume(self): - return "%s" % self.info['resume'] + return str(self._resume) def getCap(self): - return self.info['cpu_cap'] + return self.info.get('cpu_cap', 0) def getWeight(self): return self.info['cpu_weight'] def setResume(self, state): - self.info['resume'] = state + self._resume = state def getRestartCount(self): return self._readVm('xend/restart_count') @@ -891,7 +918,7 @@ class XendDomainInfo: return log.warn('Domain has crashed: name=%s id=%d.', - self.info['name'], self.domid) + self.info['name_label'], self.domid) if xroot.get_enable_dump(): self.dumpCore() @@ -910,7 +937,7 @@ class XendDomainInfo: reason = shutdown_reason(xeninfo['shutdown_reason']) log.info('Domain has shutdown: name=%s id=%d reason=%s.', - self.info['name'], self.domid, reason) + self.info['name_label'], self.domid, reason) self._clearRestart() @@ -945,7 +972,7 @@ class XendDomainInfo: if timeout < 0: log.info( "Domain shutdown timeout expired: name=%s id=%s", - self.info['name'], self.domid) + self.info['name_label'], self.domid) self.destroy() finally: self.refresh_shutdown_lock.release() @@ -965,11 +992,23 @@ class XendDomainInfo: def _maybeRestart(self, reason): # Dispatch to the correct method based upon the configured on_{reason} # behaviour. - {"destroy" : self.destroy, - "restart" : self._restart, - "preserve" : self._preserve, - "rename-restart" : self._renameRestart}[self.info['on_' + reason]]() - + actions = {"destroy" : self.destroy, + "restart" : self._restart, + "preserve" : self._preserve, + "rename-restart" : self._renameRestart} + + action_conf = { + 'poweroff': 'actions_after_shutdown', + 'reboot': 'actions_after_reboot', + 'crash': 'actions_after_crash', + } + + action_target = self.info.get(action_conf.get(reason)) + func = actions.get(action_target, None) + if func and callable(func): + func() + else: + self.destroy() # default to destroy def _renameRestart(self): self._restart(True) @@ -1008,7 +1047,7 @@ class XendDomainInfo: log.error( 'VM %s restarting too fast (%f seconds since the last ' 'restart). Refusing to restart to avoid loops.', - self.info['name'], timeout) + self.info['name_label'], timeout) self.destroy() return @@ -1055,11 +1094,11 @@ class XendDomainInfo: new_uuid = uuid.createString() new_name = 'Domain-%s' % new_uuid log.info("Renaming dead domain %s (%d, %s) to %s (%s).", - self.info['name'], self.domid, self.info['uuid'], + self.info['name_label'], self.domid, self.info['uuid'], new_name, new_uuid) self._unwatchVm() self._releaseDevices() - self.info['name'] = new_name + self.info['name_label'] = new_name self.info['uuid'] = new_uuid self.vmpath = XS_VMROOT + new_uuid self._storeVmDetails() @@ -1067,7 +1106,7 @@ class XendDomainInfo: def _preserve(self): - log.info("Preserving dead domain %s (%d).", self.info['name'], + log.info("Preserving dead domain %s (%d).", self.info['name_label'], self.domid) self._unwatchVm() self._storeDom('xend/shutdown_completed', 'True') @@ -1084,7 +1123,7 @@ class XendDomainInfo: if not corefile: this_time = time.strftime("%Y-%m%d-%H%M.%S", time.localtime()) corefile = "/var/xen/dump/%s-%s.%s.core" % (this_time, - self.info['name'], self.domid) + self.info['name_label'], self.domid) if os.path.isdir(corefile): raise XendError("Cannot dump core in a directory: %s" % @@ -1095,7 +1134,7 @@ class XendDomainInfo: corefile_incomp = corefile+'-incomplete' os.rename(corefile, corefile_incomp) log.exception("XendDomainInfo.dumpCore failed: id = %s name = %s", - self.domid, self.info['name']) + self.domid, self.info['name_label']) raise XendError("Failed to dump core: %s" % str(ex)) # @@ -1117,8 +1156,8 @@ class XendDomainInfo: @raise: VmError for invalid devices """ - for (devclass, config) in self.info.all_devices_sxpr(): - if devclass in XendDevices.valid_devices(): + for (devclass, config) in self.info.get('devices', {}).values(): + if devclass in XendDevices.valid_devices(): log.info("createDevice: %s : %s" % (devclass, config)) self._createDevice(devclass, config) @@ -1139,7 +1178,7 @@ class XendDomainInfo: # there's nothing more we can do. log.exception( "Device release failed: %s; %s; %s", - self.info['name'], devclass, dev) + self.info['name_label'], devclass, dev) if t.commit(): break @@ -1211,11 +1250,12 @@ class XendDomainInfo: log.debug('XendDomainInfo.constructDomain') - hvm = (self._infoIsSet('image') and - sxp.name(self.info['image']) == "hvm") + image_cfg = self.info.get('image', {}) + hvm = image_cfg.has_key('hvm') + if hvm: info = xc.xeninfo() - if not 'hvm' in info['xen_caps']: + if 'hvm' not in info['xen_caps']: raise VmError("HVM guest support is unavailable: is VT/AMD-V " "supported by your CPU and enabled in your " "BIOS?") @@ -1228,14 +1268,14 @@ class XendDomainInfo: if self.domid < 0: raise VmError('Creating domain failed: name=%s' % - self.info['name']) + self.info['name_label']) self.dompath = GetDomainPath(self.domid) self._recreateDom() # Set maximum number of vcpus in domain - xc.domain_max_vcpus(self.domid, int(self.info['vcpus'])) + xc.domain_max_vcpus(self.domid, int(self.info['vcpus_number'])) def _introduceDomain(self): @@ -1256,7 +1296,7 @@ class XendDomainInfo: # if we have a boot loader but no image, then we need to set things # up by running the boot loader non-interactively - if self._infoIsSet('bootloader') and not self._infoIsSet('image'): + if self.info.get('bootloader') and self.info.get('image'): self._configureBootloader() if not self._infoIsSet('image'): @@ -1264,8 +1304,9 @@ class XendDomainInfo: try: self.image = image.create(self, + self.info, self.info['image'], - self.info.all_devices_sxpr()) + self.info['devices']) localtime = self.info.get('localtime', 0) if localtime is not None and localtime == 1: @@ -1284,12 +1325,12 @@ class XendDomainInfo: # the various headrooms necessary, given the raw configured # values. maxmem, memory, and shadow are all in KiB. maxmem = self.image.getRequiredAvailableMemory( - self.info['maxmem'] * 1024) + self.info['memory_static_min'] * 1024) memory = self.image.getRequiredAvailableMemory( - self.info['memory'] * 1024) + self.info['memory_static_max'] * 1024) shadow = self.image.getRequiredShadowMemory( self.info['shadow_memory'] * 1024, - self.info['maxmem'] * 1024) + self.info['memory_static_max'] * 1024) # Round shadow up to a multiple of a MiB, as shadow_mem_control # takes MiB and we must not round down and end up under-providing. @@ -1317,7 +1358,7 @@ class XendDomainInfo: self._createDevices() - if self.info['bootloader'] not in [None, 'kernel_external']: + if self.info['bootloader']: self.image.cleanupBootloading() self.info['start_time'] = time.time() @@ -1325,7 +1366,7 @@ class XendDomainInfo: self._stateSet(DOM_STATE_RUNNING) except RuntimeError, exn: log.exception("XendDomainInfo.initDomain: exception occurred") - if self.info['bootloader'] not in [None, 'kernel_external'] \ + if self.info['bootloader'] not in (None, 'kernel_external') \ and self.image is not None: self.image.cleanupBootloading() raise VmError(str(exn)) @@ -1338,7 +1379,6 @@ class XendDomainInfo: self.refresh_shutdown_lock.acquire() try: self.unwatchShutdown() - self._releaseDevices() if self.image: @@ -1459,14 +1499,14 @@ class XendDomainInfo: def _configureBootloader(self): """Run the bootloader if we're configured to do so.""" - if not self.info['bootloader']: + if not self.info.get('bootloader'): return blcfg = None # FIXME: this assumes that we want to use the first disk device - for (n, c) in self.info.all_devices_sxpr(): - if not n or not c or not(n in ["vbd", "tap"]): + for devuuid, (devtype, devinfo) in self.info.all_devices_sxpr(): + if not devtype or not devinfo or devtype not in ('vbd', 'tap'): continue - disk = sxp.child_value(c, "uname") + disk = devinfo.get('uname') if disk is None: continue fn = blkdev_uname_to_file(disk) @@ -1478,7 +1518,8 @@ class XendDomainInfo: msg = "Had a bootloader specified, but can't find disk" log.error(msg) raise VmError(msg) - self.info['image'] = blcfg + + self.info.update_with_image_sxp(blcfg) # # VM Functions @@ -1516,7 +1557,8 @@ class XendDomainInfo: if arch.type == "x86": # 1MB per vcpu plus 4Kib/Mib of RAM. This is higher than # the minimum that Xen would allocate if no value were given. - overhead_kb = self.info['vcpus'] * 1024 + self.info['maxmem'] * 4 + overhead_kb = self.info['vcpus_number'] * 1024 + \ + self.info['memory_static_max'] * 4 overhead_kb = ((overhead_kb + 1023) / 1024) * 1024 # The domain might already have some shadow memory overhead_kb -= xc.shadow_mem_control(self.domid) * 1024 @@ -1558,12 +1600,15 @@ class XendDomainInfo: def _storeVmDetails(self): to_store = {} - for k in VM_STORE_ENTRIES: - if self._infoIsSet(k[0]): - to_store[k[0]] = str(self.info[k[0]]) + for key in XendConfig.LEGACY_XENSTORE_VM_PARAMS: + info_key = XendConfig.LEGACY_CFG_TO_XENAPI_CFG.get(key, key) + if self._infoIsSet(info_key): + to_store[key] = str(self.info[info_key]) - if self._infoIsSet('image'): - to_store['image'] = sxp.to_string(self.info['image']) + if self.info.get('image'): + image_sxpr = self.info.image_sxpr() + if image_sxpr: + to_store['image'] = sxp.to_string(image_sxpr) if self._infoIsSet('security'): secinfo = self.info['security'] @@ -1656,6 +1701,7 @@ class XendDomainInfo: #create new security element self.info.update({'security': [['ssidref', str(info['ssidref'])]]}) + #ssidref field not used any longer if 'ssidref' in info: info.pop('ssidref') @@ -1663,8 +1709,7 @@ class XendDomainInfo: # make sure state is reset for info # TODO: we should eventually get rid of old_dom_states - self.info.update(info) - self.info.validate() + self.info.update_config(info) if refresh: self.refreshShutdown(info) @@ -1673,7 +1718,7 @@ class XendDomainInfo: str(self.domid), self.info) def sxpr(self, ignore_store = False): - result = self.info.get_sxp(domain = self, + result = self.info.to_sxp(domain = self, ignore_devices = ignore_store) if not ignore_store and self.dompath: @@ -1695,9 +1740,15 @@ class XendDomainInfo: return dom_uuid def get_memory_static_max(self): - return self.info['maxmem'] + return self.info['memory_static_max'] def get_memory_static_min(self): - return self.info['memory'] + return self.info['memory_static_min'] + def get_memory_dynamic_max(self): + return self.info['memory_dynamic_min'] + def get_memory_dynamic_min(self): + return self.info['memory_static_min'] + + def get_vcpus_policy(self): sched_id = xc.sched_id_get() if sched_id == xen.lowlevel.xc.XEN_SCHEDULER_SEDF: @@ -1717,21 +1768,17 @@ class XendDomainInfo: def get_platform_keymap(self): return '' def get_platform_serial(self): - return '' # TODO + return self.info['platform_serial'] def get_platform_localtime(self): - return False # TODO + return self.info['platform_localtime'] def get_platform_clock_offset(self): - return False # TODO + return self.info['platform_clock_offset'] def get_platform_enable_audio(self): - return False # TODO + return self.info['platform_enable_audio'] def get_builder(self): - return 'Linux' # TODO + return self.info['builder'] def get_boot_method(self): - bootloader = self.info['bootloader'] - if not bootloader or bootloader not in XEN_API_BOOT_TYPE: - return 'kernel_external' - return bootloader - + return self.info['boot_method'] def get_kernel_image(self): return self.info['kernel_kernel'] def get_kernel_initrd(self): @@ -1748,25 +1795,26 @@ class XendDomainInfo: return {} # TODO def get_on_shutdown(self): - after_shutdown = self.info.get('on_poweroff') + after_shutdown = self.info.get('action_after_shutdown') if not after_shutdown or after_shutdown not in XEN_API_ON_NORMAL_EXIT: return XEN_API_ON_NORMAL_EXIT[-1] return after_shutdown def get_on_reboot(self): - after_reboot = self.info.get('on_reboot') + after_reboot = self.info.get('action_after_reboot') if not after_reboot or after_reboot not in XEN_API_ON_NORMAL_EXIT: return XEN_API_ON_NORMAL_EXIT[-1] return after_reboot def get_on_suspend(self): - after_suspend = self.info.get('on_suspend') # TODO: not supported + # TODO: not supported + after_suspend = self.info.get('action_after_suspend') if not after_suspend or after_suspend not in XEN_API_ON_NORMAL_EXIT: return XEN_API_ON_NORMAL_EXIT[-1] return after_suspend def get_on_crash(self): - after_crash = self.info.get('on_crash') + after_crash = self.info.get('action_after_crash') if not after_crash or after_crash not in XEN_API_ON_CRASH_BEHAVIOUR: return XEN_API_ON_CRASH_BEHAVIOUR[0] return after_crash @@ -1780,7 +1828,7 @@ class XendDomainInfo: @rtype: dictionary """ - dev_type_config = self.info['device'].get(dev_uuid) + dev_type_config = self.info['devices'].get(dev_uuid) # shortcut if the domain isn't started because # the devcontrollers will have no better information @@ -1840,7 +1888,7 @@ class XendDomainInfo: config['IO_bandwidth_incoming_kbs'] = 0.0 config['IO_bandwidth_outgoing_kbs'] = 0.0 - if dev_class =='vbd': + if dev_class == 'vbd': config['VDI'] = '' # TODO config['device'] = config.get('dev', '') config['driver'] = 'paravirtualised' # TODO @@ -1984,8 +2032,8 @@ class XendDomainInfo: def __str__(self): return '' % \ - (str(self.domid), self.info['name'], - str(self.info['memory']), DOM_STATES[self.state]) + (str(self.domid), self.info['name_label'], + str(self.info['memory_static_min']), DOM_STATES[self.state]) __repr__ = __str__ diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index 546e6eca38..98397d76ca 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -23,7 +23,6 @@ import math import signal import xen.lowlevel.xc -from xen.xend import sxp from xen.xend.XendError import VmError, XendError from xen.xend.XendLogging import log from xen.xend.server.netif import randomMAC @@ -31,19 +30,18 @@ from xen.xend.xenstore.xswatch import xswatch from xen.xend import arch from xen.xend import FlatDeviceTree - xc = xen.lowlevel.xc.xc() - MAX_GUEST_CMDLINE = 1024 -def create(vm, imageConfig, deviceConfig): +def create(vm, vmConfig, imageConfig, deviceConfig): """Create an image handler for a vm. @return ImageHandler instance """ - return findImageHandlerClass(imageConfig)(vm, imageConfig, deviceConfig) + return findImageHandlerClass(imageConfig)(vm, vmConfig, imageConfig, + deviceConfig) class ImageHandler: @@ -66,34 +64,20 @@ class ImageHandler: ostype = None - def __init__(self, vm, imageConfig, deviceConfig): + def __init__(self, vm, vmConfig, imageConfig, deviceConfig): self.vm = vm self.kernel = None self.ramdisk = None self.cmdline = None - self.configure(imageConfig, deviceConfig) + self.configure(vmConfig, imageConfig, deviceConfig) - def configure(self, imageConfig, _): + def configure(self, vmConfig, imageConfig, _): """Config actions common to all unix-like domains.""" - - def get_cfg(name, default = None): - return sxp.child_value(imageConfig, name, default) - - self.kernel = get_cfg("kernel") - self.cmdline = "" - ip = get_cfg("ip") - if ip: - self.cmdline += " ip=" + ip - root = get_cfg("root") - if root: - self.cmdline += " root=" + root - args = get_cfg("args") - if args: - self.cmdline += " " + args - self.ramdisk = get_cfg("ramdisk", '') - + self.kernel = vmConfig['kernel_kernel'] + self.cmdline = vmConfig['kernel_args'] + self.ramdisk = vmConfig['kernel_initrd'] self.vm.storeVm(("image/ostype", self.ostype), ("image/kernel", self.kernel), ("image/cmdline", self.cmdline), @@ -214,8 +198,8 @@ class PPC_LinuxImageHandler(LinuxImageHandler): ostype = "linux" - def configure(self, imageConfig, deviceConfig): - LinuxImageHandler.configure(self, imageConfig, deviceConfig) + def configure(self, vmConfig, imageConfig, deviceConfig): + LinuxImageHandler.configure(self, vmConfig, imageConfig, deviceConfig) self.imageConfig = imageConfig def buildDomain(self): @@ -248,25 +232,26 @@ class PPC_LinuxImageHandler(LinuxImageHandler): class HVMImageHandler(ImageHandler): - def __init__(self, vm, imageConfig, deviceConfig): - ImageHandler.__init__(self, vm, imageConfig, deviceConfig) + def __init__(self, vm, vmConfig, imageConfig, deviceConfig): + ImageHandler.__init__(self, vm, vmConfig, imageConfig, deviceConfig) self.shutdownWatch = None - def configure(self, imageConfig, deviceConfig): - ImageHandler.configure(self, imageConfig, deviceConfig) + def configure(self, vmConfig, imageConfig, deviceConfig): + ImageHandler.configure(self, vmConfig, imageConfig, deviceConfig) info = xc.xeninfo() - if not 'hvm' in info['xen_caps']: + if 'hvm' not in info['xen_caps']: raise VmError("HVM guest support is unavailable: is VT/AMD-V " "supported by your CPU and enabled in your BIOS?") self.dmargs = self.parseDeviceModelArgs(imageConfig, deviceConfig) - self.device_model = sxp.child_value(imageConfig, 'device_model') + self.device_model = imageConfig['hvm'].get('device_model') if not self.device_model: raise VmError("hvm: missing device model") - self.display = sxp.child_value(imageConfig, 'display') - self.xauthority = sxp.child_value(imageConfig, 'xauthority') - self.vncconsole = sxp.child_value(imageConfig, 'vncconsole') + + self.display = imageConfig['hvm'].get('display') + self.xauthority = imageConfig['hvm'].get('xauthority') + self.vncconsole = imageConfig['hvm'].get('vncconsole') self.vm.storeVm(("image/dmargs", " ".join(self.dmargs)), ("image/device-model", self.device_model), @@ -276,9 +261,9 @@ class HVMImageHandler(ImageHandler): self.dmargs += self.configVNC(imageConfig) - self.pae = int(sxp.child_value(imageConfig, 'pae', 1)) - self.acpi = int(sxp.child_value(imageConfig, 'acpi', 1)) - self.apic = int(sxp.child_value(imageConfig, 'apic', 1)) + self.pae = imageConfig['hvm'].get('pae', 0) + self.acpi = imageConfig['hvm'].get('acpi', 0) + self.apic = imageConfig['hvm'].get('apic', 0) def buildDomain(self): store_evtchn = self.vm.getStorePort() @@ -312,8 +297,12 @@ class HVMImageHandler(ImageHandler): 'localtime', 'serial', 'stdvga', 'isa', 'vcpus', 'acpi', 'usb', 'usbdevice', 'keymap' ] ret = [] + hvmDeviceConfig = imageConfig['hvm']['devices'] + for a in dmargs: - v = sxp.child_value(imageConfig, a) + v = hvmDeviceConfig.get(a) + if a == 'vcpus': + v = hvmDeviceConfig.get('vcpus_number') # python doesn't allow '-' in variable names if a == 'stdvga': a = 'std-vga' @@ -328,7 +317,7 @@ class HVMImageHandler(ImageHandler): ret.append("-%s" % a) ret.append("%s" % v) - if a in ['fda', 'fdb' ]: + if a in ['fda', 'fdb']: if v: if not os.path.isabs(v): raise VmError("Floppy file %s does not exist." % v) @@ -336,26 +325,27 @@ class HVMImageHandler(ImageHandler): # Handle disk/network related options mac = None - ret = ret + ["-domain-name", "%s" % self.vm.info['name']] + ret = ret + ["-domain-name", str(self.vm.info['name_label'])] nics = 0 - for (name, info) in deviceConfig: - if name == 'vbd': - uname = sxp.child_value(info, 'uname') + + for devuuid, (devtype, devinfo) in deviceConfig.items(): + if devtype == 'vbd': + uname = devinfo['uname'] if uname is not None and 'file:' in uname: (_, vbdparam) = string.split(uname, ':', 1) if not os.path.isfile(vbdparam): raise VmError('Disk image does not exist: %s' % vbdparam) - if name == 'vif': - type = sxp.child_value(info, 'type') - if type != 'ioemu': + if devtype == 'vif': + dtype = devinfo.get('type', 'ioemu') + if dtype != 'ioemu': continue nics += 1 - mac = sxp.child_value(info, 'mac') + mac = devinfo.get('mac') if mac == None: mac = randomMAC() - bridge = sxp.child_value(info, 'bridge', 'xenbr0') - model = sxp.child_value(info, 'model', 'rtl8139') + bridge = devinfo.get('bridge', 'xenbr0') + model = devinfo.get('model', 'rtl8139') ret.append("-net") ret.append("nic,vlan=%d,macaddr=%s,model=%s" % (nics, mac, model)) @@ -363,31 +353,32 @@ class HVMImageHandler(ImageHandler): ret.append("tap,vlan=%d,bridge=%s" % (nics, bridge)) return ret - def configVNC(self, config): + def configVNC(self, imageConfig): # Handle graphics library related options - vnc = sxp.child_value(config, 'vnc') - sdl = sxp.child_value(config, 'sdl') + vnc = imageConfig.get('vnc') + sdl = imageConfig.get('sdl') ret = [] - nographic = sxp.child_value(config, 'nographic') + nographic = imageConfig.get('nographic') # get password from VM config (if password omitted, None) - vncpasswd_vmconfig = sxp.child_value(config, 'vncpasswd') + vncpasswd_vmconfig = imageConfig.get('vncpasswd') if nographic: ret.append('-nographic') return ret if vnc: - vncdisplay = int(sxp.child_value(config, 'vncdisplay', - self.vm.getDomid())) + vncdisplay = imageConfig.get('vncdisplay', + int(self.vm.getDomid())) + vncunused = imageConfig.get('vncunused') - vncunused = sxp.child_value(config, 'vncunused') if vncunused: ret += ['-vncunused'] else: ret += ['-vnc', '%d' % vncdisplay] - vnclisten = sxp.child_value(config, 'vnclisten') + vnclisten = imageConfig.get('vnclisten') + if not(vnclisten): vnclisten = (xen.xend.XendRoot.instance(). get_vnclisten_address()) @@ -423,21 +414,26 @@ class HVMImageHandler(ImageHandler): if self.vncconsole: args = args + ([ "-vncviewer" ]) log.info("spawning device models: %s %s", self.device_model, args) + # keep track of pid and spawned options to kill it later self.pid = os.spawnve(os.P_NOWAIT, self.device_model, args, env) log.info("device model pid: %d", self.pid) def destroy(self): - self.unregister_shutdown_watch(); + self.unregister_shutdown_watch() if not self.pid: return - os.kill(self.pid, signal.SIGKILL) - os.waitpid(self.pid, 0) + try: + os.kill(self.pid, signal.SIGKILL) + os.waitpid(self.pid, 0) + except OSError, e: + log.warning("Unable to kill device model (pid: %d)" % self.pid) + self.pid = 0 def register_shutdown_watch(self): """ add xen store watch on control/shutdown """ - self.shutdownWatch = xswatch(self.vm.dompath + "/control/shutdown", \ - self.hvm_shutdown) + self.shutdownWatch = xswatch(self.vm.dompath + "/control/shutdown", + self.hvm_shutdown) log.debug("hvm shutdown watch registered") def unregister_shutdown_watch(self): @@ -529,10 +525,10 @@ def findImageHandlerClass(image): @param image config @return ImageHandler subclass or None """ - type = sxp.name(image) - if type is None: + image_type = image['type'] + if image_type is None: raise VmError('missing image type') try: - return _handlers[arch.type][type] + return _handlers[arch.type][image_type] except KeyError: - raise VmError('unknown image type: ' + type) + raise VmError('unknown image type: ' + image_type) diff --git a/tools/python/xen/xend/server/DevController.py b/tools/python/xen/xend/server/DevController.py index cbe3b18845..646e19d9de 100644 --- a/tools/python/xen/xend/server/DevController.py +++ b/tools/python/xen/xend/server/DevController.py @@ -17,6 +17,7 @@ #============================================================================ from threading import Event +import types from xen.xend import sxp from xen.xend.XendError import VmError @@ -86,7 +87,7 @@ class DevController: import xen.xend.XendDomain xd = xen.xend.XendDomain.instance() - backdom_name = sxp.child_value(config, 'backend') + backdom_name = config.get('backend') if backdom_name is None: backdom = xen.xend.XendDomain.DOM0_ID else: @@ -223,7 +224,7 @@ class DevController: configDict = self.getDeviceConfiguration(devid) sxpr = [self.deviceClass] for key, val in configDict.items(): - if type(val) == type(list()): + if isinstance(val, (types.ListType, types.TupleType)): for v in val: sxpr.append([key, v]) else: @@ -405,7 +406,7 @@ class DevController: import xen.xend.XendDomain xd = xen.xend.XendDomain.instance() - backdom_name = sxp.child_value(config, 'backend') + backdom_name = config.get('backend') if backdom_name: backdom = xd.domain_lookup_nr(backdom_name) else: diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py index 6bd49acfc9..16e2c5052d 100644 --- a/tools/python/xen/xend/server/blkif.py +++ b/tools/python/xen/xend/server/blkif.py @@ -21,7 +21,6 @@ import string from xen.util import blkif from xen.util import security -from xen.xend import sxp from xen.xend.XendError import VmError from xen.xend.server.DevController import DevController @@ -37,9 +36,9 @@ class BlkifController(DevController): def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" - uname = sxp.child_value(config, 'uname', '') - dev = sxp.child_value(config, 'dev', '') - + uname = config.get('uname', '') + dev = config.get('dev', '') + if 'ioemu:' in dev: (_, dev) = string.split(dev, ':', 1) try: @@ -59,17 +58,17 @@ class BlkifController(DevController): except ValueError: (typ, params) = ("", "") - mode = sxp.child_value(config, 'mode', 'r') + mode = config.get('mode', 'r') if mode not in ('r', 'w', 'w!'): raise VmError('Invalid mode') - back = { 'dev' : dev, - 'type' : typ, - 'params' : params, - 'mode' : mode - } + back = {'dev' : dev, + 'type' : typ, + 'params' : params, + 'mode' : mode, + } - uuid = sxp.child_value(config, 'uuid') + uuid = config.get('uuid') if uuid: back['uuid'] = uuid diff --git a/tools/python/xen/xend/server/iopif.py b/tools/python/xen/xend/server/iopif.py index 96651a7c95..3b1a263736 100644 --- a/tools/python/xen/xend/server/iopif.py +++ b/tools/python/xen/xend/server/iopif.py @@ -22,7 +22,6 @@ import types import xen.lowlevel.xc -from xen.xend import sxp from xen.xend.XendError import VmError from xen.xend.server.DevController import DevController @@ -49,13 +48,12 @@ class IOPortsController(DevController): def __init__(self, vm): DevController.__init__(self, vm) - def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" def get_param(field): try: - val = sxp.child_value(config, field) + val = config.get(field) if not val: raise VmError('ioports: Missing %s config setting' % field) diff --git a/tools/python/xen/xend/server/irqif.py b/tools/python/xen/xend/server/irqif.py index 6e539dbab9..346ad7cf4d 100644 --- a/tools/python/xen/xend/server/irqif.py +++ b/tools/python/xen/xend/server/irqif.py @@ -45,7 +45,7 @@ class IRQController(DevController): def get_param(field): try: - val = sxp.child_value(config, field) + val = config.get(field) if not val: raise VmError('irq: Missing %s config setting' % field) diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py index 4c7e359617..a20929a0d9 100644 --- a/tools/python/xen/xend/server/netif.py +++ b/tools/python/xen/xend/server/netif.py @@ -24,7 +24,6 @@ import os import random import re -from xen.xend import sxp from xen.xend import XendRoot from xen.xend.server.DevController import DevController @@ -139,22 +138,15 @@ class NetifController(DevController): def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" - def _get_config_ipaddr(config): - val = [] - for ipaddr in sxp.children(config, elt='ip'): - val.append(sxp.child0(ipaddr)) - return val - script = os.path.join(xroot.network_script_dir, - sxp.child_value(config, 'script', - xroot.get_vif_script())) - typ = sxp.child_value(config, 'type') - bridge = sxp.child_value(config, 'bridge') - mac = sxp.child_value(config, 'mac') - vifname = sxp.child_value(config, 'vifname') - rate = sxp.child_value(config, 'rate') - uuid = sxp.child_value(config, 'uuid') - ipaddr = _get_config_ipaddr(config) + config.get('script', xroot.get_vif_script())) + typ = config.get('type') + bridge = config.get('bridge') + mac = config.get('mac') + vifname = config.get('vifname') + rate = config.get('rate') + uuid = config.get('uuid') + ipaddr = config.get('ip') devid = self.allocateDeviceID() diff --git a/tools/python/xen/xend/server/pciif.py b/tools/python/xen/xend/server/pciif.py index eaab90529f..68af9d78cc 100644 --- a/tools/python/xen/xend/server/pciif.py +++ b/tools/python/xen/xend/server/pciif.py @@ -53,60 +53,29 @@ class PciController(DevController): def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" - #log.debug('pci config='+sxp.to_string(config)) - - def get_param(config, field, default=None): + def parse_hex(val): try: - val = sxp.child_value(config, field) - - if not val: - if default==None: - raise VmError('pci: Missing %s config setting' % field) - else: - return default - if isinstance(val, types.StringTypes): return int(val, 16) else: return val - except: - if default==None: - raise VmError('pci: Invalid config setting %s: %s' % - (field, val)) - else: - return default - - back = {} - - val = sxp.child_value(config, 'dev') - if isinstance(val, (types.ListType, types.TupleType)): - pcidevid = 0 - for dev_config in sxp.children(config, 'dev'): - domain = get_param(dev_config, 'domain', 0) - bus = get_param(dev_config,'bus') - slot = get_param(dev_config,'slot') - func = get_param(dev_config,'func') - - self.setupDevice(domain, bus, slot, func) - - back['dev-%i' % pcidevid]="%04x:%02x:%02x.%02x"% \ - (domain, bus, slot, func) - pcidevid+=1 + except ValueError: + return None - back['num_devs']=str(pcidevid) - - else: - # Xen 2.0 configuration compatibility - domain = get_param(config, 'domain', 0) - bus = get_param(config, 'bus') - slot = get_param(config, 'dev') - func = get_param(config, 'func') - + back = {} + pcidevid = 0 + for pci_config in config.get('devs', []): + domain = parse_hex(pci_config.get('domain', 0)) + bus = parse_hex(pci_config.get('bus', 0)) + slot = parse_hex(pci_config.get('slot', 0)) + func = parse_hex(pci_config.get('func', 0)) self.setupDevice(domain, bus, slot, func) + back['dev-%i' % pcidevid] = "%04x:%02x:%02x.%02x" % \ + (domain, bus, slot, func) + pcidevid += 1 - back['dev-0']="%04x:%02x:%02x.%02x"%(domain, bus, slot, func) - back['num_devs']=str(1) - + back['num_devs']=str(pcidevid) + back['uuid'] = config.get('uuid','') return (0, back, {}) def getDeviceConfiguration(self, devid): @@ -129,7 +98,8 @@ class PciController(DevController): 'slot': '0x%(slot)s' % pci_dev_info, 'func': '0x%(func)s' % pci_dev_info}) - result['dev'] = pci_devs + result['devs'] = pci_devs + result['uuid'] = self.readBackend(devid, 'uuid') return result def configuration(self, devid): @@ -142,7 +112,8 @@ class PciController(DevController): sxpr = [self.deviceClass] # remove devs - devs = configDict.pop('dev', []) + devs = configDict.pop('devs', []) + for dev in devs: dev_sxpr = ['dev'] for dev_item in dev.items(): diff --git a/tools/python/xen/xend/server/pciquirk.py b/tools/python/xen/xend/server/pciquirk.py index ea53eee5b2..c0a4a68c83 100644 --- a/tools/python/xen/xend/server/pciquirk.py +++ b/tools/python/xen/xend/server/pciquirk.py @@ -15,25 +15,24 @@ class PCIQuirk: self.device = device self.subvendor = subvendor self.subdevice = subdevice - self.domain = domain - self.bus = bus - self.slot = slot - self.func = func + self.domain = domain + self.bus = bus + self.slot = slot + self.func = func self.devid = "%04x:%04x:%04x:%04x" % (vendor, device, subvendor, subdevice) - self.pciid = "%04x:%02x:%02x.%01x" % (domain, bus, slot, func) + self.pciid = "%04x:%02x:%02x.%01x" % (domain, bus, slot, func) + self.quirks = self.__getQuirksByID() - self.quirks = self.__getQuirksByID( ) - - self.__sendQuirks( ) - self.__sendPermDevs( ) + self.__sendQuirks() + self.__sendPermDevs() def __matchPCIdev( self, list ): ret = False if list == None: return False for id in list: - if id.startswith( self.devid[:9] ): # id's vendor and device ID match + if id.startswith(self.devid[:9]): # id's vendor and device ID match skey = id.split(':') size = len(skey) if (size == 2): # subvendor/subdevice not suplied @@ -41,13 +40,13 @@ class PCIQuirk: break elif (size == 4): # check subvendor/subdevice # check subvendor - subven = '%04x' % self.subvendor + subven = '%04x' % self.subvendor if ((skey[2] != 'FFFF') and (skey[2] != 'ffff') and (skey[2] != subven)): continue # check subdevice - subdev = '%04x' % self.subdevice + subdev = '%04x' % self.subdevice if ((skey[3] != 'FFFF') and (skey[3] != 'ffff') and (skey[3] != subdev)): @@ -101,8 +100,8 @@ class PCIQuirk: self.slot, self.func, quirk) ) f.close() except Exception, e: - raise VmError("pci: failed to open/write/close quirks sysfs " + \ - "node - " + str(e)) + raise VmError("pci: failed to open/write/close quirks " + + "sysfs node - " + str(e)) def __devIsUnconstrained( self ): if os.path.exists(PERMISSIVE_CONFIG_FILE): @@ -126,20 +125,22 @@ class PCIQuirk: devices = child_at(child(pci_perm_dev_config, 'unconstrained_dev_ids'),0) if self.__matchPCIdev( devices ): - log.debug("Permissive mode enabled for PCI device [%s]" % self.devid) + log.debug("Permissive mode enabled for PCI device [%s]" % + self.devid) return True - log.debug("Permissive mode NOT enabled for PCI device [%s]" % self.devid) + log.debug("Permissive mode NOT enabled for PCI device [%s]" % + self.devid) return False def __sendPermDevs(self): if self.__devIsUnconstrained( ): - log.debug("Unconstrained device: %04x:%02x:%02x.%1x" % (self.domain, - self.bus, self.slot, self.func)) + log.debug("Unconstrained device: %04x:%02x:%02x.%1x" % + (self.domain, self.bus, self.slot, self.func)) try: f = file(PERMISSIVE_SYSFS_NODE ,"w") f.write( "%04x:%02x:%02x.%1x" % (self.domain, self.bus, - self.slot, self.func) ) + self.slot, self.func)) f.close() except Exception, e: - raise VmError("pci: failed to open/write/close permissive " + \ - "sysfs node: " + str(e)) + raise VmError("pci: failed to open/write/close permissive " + + "sysfs node: " + str(e)) diff --git a/tools/python/xen/xend/server/tests/test_controllers.py b/tools/python/xen/xend/server/tests/test_controllers.py index 16b7941e5a..aa57f6321c 100644 --- a/tools/python/xen/xend/server/tests/test_controllers.py +++ b/tools/python/xen/xend/server/tests/test_controllers.py @@ -21,13 +21,13 @@ class test_controllers(unittest.TestCase): def testNetif(self): controller = self.controllerInstance(netif.NetifController) - self.assertNetif(controller.getDeviceDetails(['vif']), None) + self.assertNetif(controller.getDeviceDetails({}), None) self.assertNetif( - controller.getDeviceDetails( - ['vif', ['mac', 'aa:bb:cc:dd:ee:ff']]), + controller.getDeviceDetails({'mac': 'aa:bb:cc:dd:ee:ff'}), 'aa:bb:cc:dd:ee:ff') + def assertNetif(self, results, expectedMac): (devid, backdets, frontdets) = results diff --git a/tools/python/xen/xend/server/tpmif.py b/tools/python/xen/xend/server/tpmif.py index 494a197b8e..c2a5f1f64b 100644 --- a/tools/python/xen/xend/server/tpmif.py +++ b/tools/python/xen/xend/server/tpmif.py @@ -18,10 +18,8 @@ # Copyright (C) 2005 XenSource Ltd #============================================================================ -"""Support for virtual TPM interfaces. -""" +"""Support for virtual TPM interfaces.""" -from xen.xend import sxp from xen.xend import XendRoot from xen.xend.XendLogging import log from xen.xend.XendError import XendError @@ -49,12 +47,12 @@ class TPMifController(DevController): """@see DevController.getDeviceDetails""" devid = self.allocateDeviceID() - inst = int(sxp.child_value(config, 'pref_instance', '-1')) + inst = int(config.get('pref_instance', -1)) if inst == -1: - inst = int(sxp.child_value(config, 'instance' , '0')) + inst = int(config.get('instance', 0)) - typ = sxp.child_value(config, 'type') - uuid = sxp.child_value(config, 'uuid') + typ = config.get('type') + uuid = config.get('uuid') log.info("The domain has a TPM with pref. instance %d and devid %d.", inst, devid) diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 93d2fe1029..9982dc3388 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -581,8 +581,8 @@ def parse_doms_info(info): return { 'domid' : get_info('domid', str, ''), 'name' : get_info('name', str, '??'), - 'mem' : get_info('memory_dynamic_max', int, 0), - 'vcpus' : get_info('online_vcpus', int, 0), + 'mem' : get_info('memory_dynamic_min', int, 0), + 'vcpus' : get_info('vcpus', int, 0), 'state' : get_info('state', str, ''), 'cpu_time' : get_info('cpu_time', float, 0), 'up_time' : get_info('up_time', float, -1), -- 2.30.2